import Module from "./Module"
import TypeLookup from "../utils/TypeLookup"
import o from "../packages/76870"
import funcUtil from "../utils/func.util"
import browserUtil from "../utils/browser.util"
class InputPointer {
  config: any
  canvasData: CanvasData
  handledTouchesAsPointer: number
  lastTouchEnd: number
  activeButtons: number
  preventDoubleTap: (e: any) => void
  static doubleTapThreshold: number
  preventMultiTouchGesture: (e: any) => void
  onEventCallback: any
  constructor(e, t: HTMLElement, i, n) {
    this.config = e
    this.canvasData = i
    this.handledTouchesAsPointer = 0
    this.lastTouchEnd = 0
    this.activeButtons = o.r3.NONE
    this.preventDoubleTap = e => {
      e.cancelable && e.timeStamp - this.lastTouchEnd <= InputPointer.doubleTapThreshold && e.preventDefault(), (this.lastTouchEnd = e.timeStamp)
    }
    this.preventMultiTouchGesture = e => {
      const t = e.touches && e.touches.length > 1,
        i = "scale" in e && 1 !== e.scale
      ;(t || i) && e.cancelable && e.preventDefault()
    }
    this.onEventCallback = n
    window.PointerEvent ||
      (t.addEventListener("mousedown", e => this.onMouseDown(e)),
      t.addEventListener("mouseup", e => this.onMouseUp(e)),
      t.addEventListener("mousemove", e => this.onMouseMove(e)),
      t.addEventListener("mouseenter", e => this.onMouseEnter(e)))
    t.addEventListener("contextmenu", e => e.preventDefault())
    t.addEventListener("touchstart", e => this.onTouchStart(e))
    t.addEventListener("touchend", e => this.onTouchEnd(e))
    t.addEventListener("touchmove", e => this.onTouchMove(e))
    t.addEventListener("touchcancel", e => this.onTouchEnd(e))
    t.addEventListener("pointerdown", e => this.onPointerDown(e))
    t.addEventListener("pointerup", e => this.onPointerUp(e))
    t.addEventListener("pointermove", e => this.onPointerMove(e))
    t.addEventListener("pointercancel", e => this.onPointerUp(e))
    t.addEventListener("pointerenter", e => this.onMouseEnter(e))
    if (browserUtil.isiPhone() || browserUtil.isiPad()) {
      const e = !!funcUtil.testPassive && { passive: !1 }
      document.addEventListener("touchmove", this.preventMultiTouchGesture, e), document.addEventListener("touchend", this.preventDoubleTap, e)
    }
  }
  onMouseDown(e) {
    e.currentTarget.focus(), this.tryPreventDefault(e), (this.activeButtons |= 1 << e.button)
    const { ndc: t, client: i } = this.getPointerPosition(e)
    this.onEventCallback(new PointerButtonEvent(this.getPointerId(e), t, i, e.button, !0, pointDeviceEnum.MOUSE))
  }
  onMouseUp(e) {
    this.tryPreventDefault(e), (this.activeButtons &= ~(1 << e.button))
    const { ndc: t, client: i } = this.getPointerPosition(e)
    this.onEventCallback(new PointerButtonEvent(this.getPointerId(e), t, i, e.button, !1, pointDeviceEnum.MOUSE))
  }
  onMouseMove(e) {
    this.tryPreventDefault(e)
    const { ndc: t, client: i } = this.getPointerPosition(e)
    this.onEventCallback(new PointerMoveEvent(this.getPointerId(e), t, i, this.activeButtons, pointDeviceEnum.MOUSE))
  }
  onMouseEnter(e) {
    const t = funcUtil.checkFunc(e.buttons, o.MP.MIDDLE, o.MP.SECONDARY),
      i = (this.activeButtons ^ t) & ~t
    for (let t = o.MP.PRIMARY; t < o.MP.COUNT; ++t) {
      const n = o.AF(t)
      if (n && (i & n) > 0) {
        const { ndc: i, client: n } = this.getPointerPosition(e)
        this.onEventCallback(new PointerButtonEvent(this.getPointerId(e), i, n, t, !1, pointDeviceEnum.MOUSE))
      }
    }
    this.activeButtons = t
  }
  onTouchStart(e) {
    if ((e.currentTarget.focus(), e.cancelable && e.preventDefault(), this.handledTouchesAsPointer)) --this.handledTouchesAsPointer
    else
      for (let t = 0; t < e.changedTouches.length; t++) {
        const i = e.changedTouches.item(t),
          { ndc: n, client: s } = this.getTouchPosition(i)
        this.onEventCallback(new PointerButtonEvent(i.identifier, n, s, o.MP.PRIMARY, !0, pointDeviceEnum.TOUCH))
      }
  }
  onTouchEnd(e) {
    if ((e.cancelable && e.preventDefault(), this.handledTouchesAsPointer)) --this.handledTouchesAsPointer
    else
      for (let t = 0; t < e.changedTouches.length; t++) {
        const i = e.changedTouches.item(t),
          { ndc: n, client: s } = this.getTouchPosition(i)
        this.onEventCallback(new PointerButtonEvent(i.identifier, n, s, o.MP.PRIMARY, !1, pointDeviceEnum.TOUCH))
      }
  }
  onTouchMove(e) {
    if ((e.cancelable && e.preventDefault(), this.handledTouchesAsPointer)) --this.handledTouchesAsPointer
    else
      for (let t = 0; t < e.changedTouches.length; t++) {
        const i = e.changedTouches.item(t),
          { ndc: n, client: s } = this.getTouchPosition(i),
          r = new PointerMoveEvent(i.identifier, n, s, o.r3.PRIMARY, pointDeviceEnum.TOUCH)
        this.onEventCallback(r)
      }
  }
  onPointerDown(e) {
    switch ((this.tryPreventDefault(e), e.pointerType)) {
      case pointDeviceEnum.MOUSE:
        this.onMouseDown(e)
        break
      case pointDeviceEnum.GAMEPAD:
      case pointDeviceEnum.TOUCH:
        ++this.handledTouchesAsPointer
        const { ndc: t, client: i } = this.getPointerPosition(e)
        this.onEventCallback(new PointerButtonEvent(e.pointerId, t, i, o.MP.PRIMARY, !0, e.pointerType))
    }
  }
  onPointerUp(e) {
    switch ((this.tryPreventDefault(e), e.pointerType)) {
      case pointDeviceEnum.MOUSE:
        this.onMouseUp(e)
        break
      case pointDeviceEnum.GAMEPAD:
      case pointDeviceEnum.TOUCH:
        ++this.handledTouchesAsPointer
        const { ndc: t, client: i } = this.getPointerPosition(e)
        this.onEventCallback(new PointerButtonEvent(e.pointerId, t, i, o.MP.PRIMARY, !1, e.pointerType))
    }
  }
  onPointerMove(e) {
    switch ((this.tryPreventDefault(e), e.pointerType)) {
      case pointDeviceEnum.MOUSE:
        ;-1 !== e.button ? (this.activeButtons < e.buttons ? this.onMouseDown(e) : this.activeButtons > e.buttons && this.onMouseUp(e)) : this.onMouseMove(e)
        break
      case pointDeviceEnum.GAMEPAD:
      case pointDeviceEnum.TOUCH:
        ++this.handledTouchesAsPointer
        const { ndc: t, client: i } = this.getPointerPosition(e)
        this.onEventCallback(new PointerMoveEvent(e.pointerId, t, i, o.r3.PRIMARY, e.pointerType))
    }
  }
  getPointerId(e) {
    return e.pointerId || 0
  }
  getPointerPosition(e) {
    return {
      ndc: this.normalizePosition(e.clientX, e.clientY),
      client: {
        x: e.clientX - this.canvasData.x,
        y: e.clientY - this.canvasData.y
      }
    }
  }
  getTouchPosition(e) {
    return {
      ndc: this.normalizePosition(e.clientX, e.clientY),
      client: {
        x: e.clientX - this.canvasData.x,
        y: e.clientY - this.canvasData.y
      }
    }
  }
  normalizePosition(e, t) {
    return {
      x: (2 * (e - this.canvasData.x)) / this.canvasData.width - 1,
      y: (-2 * (t - this.canvasData.y)) / this.canvasData.height + 1
    }
  }
  tryPreventDefault(e) {
    this.config.pointerPreventDefault && e.cancelable && e.preventDefault()
  }
}
InputPointer.doubleTapThreshold = 300

import { KeyEvent } from "../event/KeyEvent"
var d = {
  59: "SEMICOLON",
  61: "PLUSEQUALS",
  173: "DASHUNDERSCORE",
  DASHUNDERSCORE: 173,
  PLUSEQUALS: 61,
  SEMICOLON: 59
}

class InputKey {
  keysDown: Record<string, boolean>
  onEventCallback: any
  constructor(e) {
    this.keysDown = {}
    this.onEventCallback = e
    this.bindHandlers()
  }
  bindHandlers() {
    if (window && window.document) {
      const e = window.document
      window.addEventListener("blur", () => {
        Object.keys(this.keysDown).forEach(e => (this.keysDown[e] = !1))
      }),
        e.addEventListener("keydown", e => {
          if (!e.ctrlKey && !e.metaKey) {
            e.preventDefault()
            const t = this.translateFirefoxKeys(e.which || e.keyCode)
            ;(this.keysDown[t] = !0), this.onEventCallback(new KeyEvent(t, KeyState.DOWN, e))
          }
        }),
        e.addEventListener("keyup", e => {
          if (!e.ctrlKey && !e.metaKey) {
            e.preventDefault()
            const t = this.translateFirefoxKeys(e.which || e.keyCode)
            this.keysDown[t] && this.onEventCallback(new KeyEvent(t, KeyState.PRESSED, e)),
              (this.keysDown[t] = !1),
              this.onEventCallback(new KeyEvent(t, KeyState.UP, e))
          }
        })
    }
  }
  translateFirefoxKeys(e) {
    switch (e) {
      case d.SEMICOLON:
        return hotKeyEnum.SEMICOLON
      case d.PLUSEQUALS:
        return hotKeyEnum.PLUSEQUALS
      case d.DASHUNDERSCORE:
        return hotKeyEnum.DASHUNDERSCORE
    }
    return e
  }
}

import * as THREE from "three"
var g = {
  0: "WAITING",
  1: "WAITINGTOEXCEEDTHRESHOLD",
  2: "GESTURING",
  GESTURING: 2,
  WAITING: 0,
  WAITINGTOEXCEEDTHRESHOLD: 1
}

class ClickGesturer {
  startPosition: THREE.Vector2
  pointerDelta: THREE.Vector2
  activeButtons: number
  state: any
  dragLimit: number
  holdLimit: number
  startTime: number
  constructor(e = 0.04, t = 300) {
    this.startPosition = new THREE.Vector2()
    this.pointerDelta = new THREE.Vector2()
    this.activeButtons = o.r3.NONE
    this.state = g.WAITING
    this.dragLimit = e
    this.holdLimit = t
  }
  start(e) {
    if ((this.state === g.WAITING && this.startPosition.copy(e.position), 0 == (e.buttons & (e.buttons - 1))))
      (this.startTime = Date.now()), (this.activeButtons = e.buttons), (this.state = g.WAITINGTOEXCEEDTHRESHOLD)
    else if (this.activeButtons) return (this.state = g.GESTURING), new ClickCancelEvent(e.position, this.activeButtons)
  }
  stop() {
    let e
    this.state === g.WAITINGTOEXCEEDTHRESHOLD &&
      Date.now() - this.startTime < this.holdLimit &&
      ((e = new ClickEvent(this.startPosition.add(this.pointerDelta), o.L2(this.activeButtons))), this.pointerDelta.set(0, 0))
    this.state = g.WAITING
    return e
  }
  onMove(e) {
    if (
      this.state === g.WAITINGTOEXCEEDTHRESHOLD &&
      (this.pointerDelta.copy(e.position).sub(this.startPosition), this.pointerDelta.length() > this.dragLimit)
    ) {
      this.state = g.GESTURING
      return new ClickCancelEvent(e.position, e.buttons)
    }
  }
  compareState(e) {
    return e === this.state
  }
}
import { DragBeginEvent, DragEndEvent, DragGestureEndEvent, DragGestureStartEvent, DragEvent } from "../event/DragEvent"
class DragGesturer {
  onEventCallback: Function
  startPosition: THREE.Vector2
  previousPosition: THREE.Vector2
  pointerDelta: THREE.Vector2
  lastPointerMove: number
  state: any
  threshold: number
  constructor(e, t = 0.04) {
    this.onEventCallback = e
    this.startPosition = new THREE.Vector2()
    this.previousPosition = new THREE.Vector2()
    this.pointerDelta = new THREE.Vector2()
    this.lastPointerMove = Date.now()
    this.state = g.WAITING
    this.threshold = t
  }
  start(e) {
    return (
      this.state === g.WAITING &&
        (this.startPosition.copy(e.position), this.previousPosition.copy(this.startPosition), (this.state = g.WAITINGTOEXCEEDTHRESHOLD)),
      new DragBeginEvent(e.position, e.buttons)
    )
  }
  stop() {
    const e = new THREE.Vector2().copy(this.previousPosition).sub(this.startPosition)
    this.state === g.GESTURING && this.onEventCallback(new DragGestureEndEvent(this.startPosition, e)),
      this.state === g.WAITING && this.pointerDelta.set(0, 0),
      (this.state = g.WAITING)
    const t = Date.now() - this.lastPointerMove
    return new DragEndEvent(this.previousPosition, this.pointerDelta, o.r3.NONE, t, e)
  }
  onMove(e) {
    let t
    return (
      this.state === g.WAITINGTOEXCEEDTHRESHOLD &&
        (this.pointerDelta.copy(e.position).sub(this.startPosition),
        this.pointerDelta.length() > this.threshold && ((this.state = g.GESTURING), this.onEventCallback(new DragGestureStartEvent(this.startPosition, e)))),
      this.state === g.GESTURING &&
        (this.pointerDelta.copy(e.position).sub(this.previousPosition),
        this.pointerDelta.length() > 0 && (t = new DragEvent(this.previousPosition, this.pointerDelta, e.buttons, e.clientPosition))),
      this.previousPosition.copy(e.position),
      (this.lastPointerMove = Date.now()),
      t
    )
  }
  compareState(e) {
    return e === this.state
  }
  compareStartPoint(e) {
    return e.equals(this.startPosition)
  }
  compareDelta(e) {
    return e.equals(this.pointerDelta)
  }
}
class PointerMovement {
  lastPosition: THREE.Vector2
  velocity: THREE.Vector2
  samePositionTicks: number
  constructor(e = new THREE.Vector2(), t = new THREE.Vector2(), i = 0) {
    ;(this.lastPosition = e), (this.velocity = t), (this.samePositionTicks = i)
  }
  start(e) {
    this.lastPosition.copy(e), this.velocity.set(0, 0), (this.samePositionTicks = 0)
  }
  update(e) {
    if (this.lastPosition.distanceTo(e) <= 0.01) {
      if ((this.samePositionTicks++, this.samePositionTicks < 2)) return
    } else this.samePositionTicks = 0
    this.velocity.copy(this.lastPosition).sub(e), this.lastPosition.copy(e)
  }
  stationary() {
    return this.samePositionTicks >= 2 || this.velocity.length() < 0.01
  }
}
const S = 2 * Math.SQRT2
class PinchGesturer {
  threshold: number
  startDistance: number
  previousDistance: number
  pointerDelta: THREE.Vector2
  lastPointerMove: number
  pinchDelta: number
  state: any
  pointerMovement1: PointerMovement
  pointerMovement2: PointerMovement
  constructor(e = 0.04) {
    this.threshold = e
    this.startDistance = 0
    this.previousDistance = 0
    this.pointerDelta = new THREE.Vector2()
    this.lastPointerMove = Date.now()
    this.pinchDelta = 0
    this.state = g.WAITING
    this.pointerMovement1 = new PointerMovement()
    this.pointerMovement2 = new PointerMovement()
  }
  start(e, t) {
    this.state === g.WAITING && (this.restart(e, t), this.pointerMovement1.start(e.position), this.pointerMovement2.start(t.position))
  }
  stop() {
    this.state = g.WAITING
    const e = Date.now() - this.lastPointerMove
    return new PinchEndEvent(this.pinchDelta, e)
  }
  onMove(e, t) {
    this.pointerMovement1.update(e.position), this.pointerMovement2.update(t.position)
    if (!(this.pointerMovement1.stationary() || this.pointerMovement2.stationary() || this.pointerMovement1.velocity.dot(this.pointerMovement2.velocity) < 0))
      return void this.restart(e, t)
    this.pointerDelta.copy(e.position).sub(t.position)
    const i = this.pointerDelta.length() / S
    if (this.state === g.WAITINGTOEXCEEDTHRESHOLD) {
      const e = i - this.startDistance
      Math.abs(e) > this.threshold && (this.state = g.GESTURING)
    }
    let n
    if (this.state === g.GESTURING) {
      const e = i - this.previousDistance
      Math.abs(e) > 0 && ((this.pinchDelta = e), (n = new PinchEvent(e)))
    }
    return (this.previousDistance = i), (this.lastPointerMove = Date.now()), n
  }
  restart(e, t) {
    ;(this.state = g.WAITINGTOEXCEEDTHRESHOLD), (this.startDistance = e.position.distanceTo(t.position) / S), (this.previousDistance = this.startDistance)
  }
}
class RotateGesturer {
  startPointerDelta: THREE.Vector2
  previousPointerDelta: THREE.Vector2
  pointerDelta: THREE.Vector2
  lastPointerMove: number
  angleWithDirection: number
  state: any
  threshold: number
  constructor(e = 0.1) {
    this.startPointerDelta = new THREE.Vector2()
    this.previousPointerDelta = new THREE.Vector2()
    this.pointerDelta = new THREE.Vector2()
    this.lastPointerMove = Date.now()
    this.angleWithDirection = 0
    this.state = g.WAITING
    this.threshold = e
  }
  start(e, t) {
    this.state === g.WAITING &&
      ((this.state = g.WAITINGTOEXCEEDTHRESHOLD),
      this.startPointerDelta.copy(e.position).sub(t.position).normalize(),
      this.pointerDelta.copy(this.startPointerDelta),
      this.previousPointerDelta.copy(this.pointerDelta))
  }
  stop() {
    this.state = g.WAITING
    const e = Date.now() - this.lastPointerMove
    return new RotateEndEvent(this.angleWithDirection, e)
  }
  onMove(e, t) {
    if ((this.pointerDelta.copy(e.position).sub(t.position).normalize(), this.state === g.WAITINGTOEXCEEDTHRESHOLD)) {
      Math.acos(funcUtil.getMax(this.pointerDelta.dot(this.startPointerDelta), -1, 1)) > this.threshold && (this.state = g.GESTURING)
    }
    let i
    if (this.state === g.GESTURING) {
      const e = Math.acos(funcUtil.getMax(this.pointerDelta.dot(this.previousPointerDelta), -1, 1))
      if (e > 0) {
        const t = this.previousPointerDelta.x * this.pointerDelta.y - this.previousPointerDelta.y * this.pointerDelta.x
        ;(this.angleWithDirection = t >= 0 ? e : -e), (i = new RotateEvent(this.angleWithDirection))
      }
    }
    return this.previousPointerDelta.copy(this.pointerDelta), (this.lastPointerMove = Date.now()), i
  }
  compareState(e) {
    return e === this.state
  }
}
const w = function (e, t) {
  if ((t.setLength(0), 0 === e.length)) return t
  let i = 0
  for (const n of e) t.add(n), i++
  return t.divideScalar(i), t
}
class MultiSwipeGesturer {
  startEpicenter: THREE.Vector2
  previousEpicenter: THREE.Vector2
  deltaEpicenter: THREE.Vector2
  currentEpicenter: THREE.Vector2
  pointerCount: number
  lastPointerMove: number
  state: any
  pointerMovements: any[]
  threshold: number
  constructor(e = 0.04) {
    ;(this.startEpicenter = new THREE.Vector2()),
      (this.previousEpicenter = new THREE.Vector2()),
      (this.deltaEpicenter = new THREE.Vector2()),
      (this.currentEpicenter = new THREE.Vector2()),
      (this.pointerCount = 0),
      (this.lastPointerMove = Date.now()),
      (this.state = g.WAITING),
      (this.pointerMovements = []),
      (this.threshold = e)
  }
  start(e) {
    this.state === g.WAITING &&
      (this.restart(e),
      (this.pointerMovements = e.map(e => new PointerMovement())),
      e.forEach((e, t) => {
        this.pointerMovements[t].start(e.position)
      }))
  }
  stop() {
    this.state = g.WAITING
    const e = this.pointerCount
    this.pointerCount = 0
    const t = Date.now() - this.lastPointerMove
    return new MultiSwipeEndEvent(e, this.currentEpicenter, this.deltaEpicenter, t)
  }
  onMove(e) {
    w(this.getPointerPositions(e), this.currentEpicenter),
      e.forEach((e, t) => {
        this.pointerMovements[t].update(e.position)
      })
    if (this.pointerMovements.find(e => e.stationary())) return void this.restart(e)
    const t = this.pointerMovements[0].velocity
    if (this.pointerMovements.find(e => t.dot(e.velocity) < 0)) return void this.restart(e)
    if (this.state === g.WAITINGTOEXCEEDTHRESHOLD) {
      this.currentEpicenter.distanceTo(this.startEpicenter) > this.threshold && (this.state = g.GESTURING)
    }
    let i
    return (
      this.state === g.GESTURING &&
        (this.deltaEpicenter.copy(this.currentEpicenter).sub(this.previousEpicenter),
        (i = new MultiSwipeEvent(e.length, this.currentEpicenter, this.deltaEpicenter))),
      this.previousEpicenter.copy(this.currentEpicenter),
      (this.lastPointerMove = Date.now()),
      i
    )
  }
  getPointerPositions(e) {
    return e.map(e => e.position)
  }
  restart(e) {
    w(this.getPointerPositions(e), this.startEpicenter),
      this.previousEpicenter.copy(this.startEpicenter),
      this.currentEpicenter.copy(this.previousEpicenter),
      (this.state = g.WAITINGTOEXCEEDTHRESHOLD),
      (this.pointerCount = e.length)
  }
}
import { ScrollEvent } from "../event/ScrollEvent"
import Logger from "../utils/Logger"
import {
  ClickCancelEvent,
  ClickEvent,
  HoverEvent,
  LongPressEndEvent,
  LongPressMoveEvent,
  LongPressProgressEvent,
  LongPressStartEvent,
  LongPressSuccessEvent,
  MultiSwipeEndEvent,
  MultiSwipeEvent,
  PinchEndEvent,
  PinchEvent,
  RotateEndEvent,
  RotateEvent,
  UnhoverEvent
} from "../event/GestureEvent"
const A = new Logger("longpress")
var O = {
  0: "IDLE",
  1: "WAITING",
  2: "STARTED",
  3: "SUCCESSFUL",
  IDLE: 0,
  STARTED: 2,
  SUCCESSFUL: 3,
  WAITING: 1
}

class LongPressGesturer {
  onEventCallback: any
  state: any
  ndcStartPosition: THREE.Vector2
  pointerDelta: THREE.Vector2
  ndcPosition: THREE.Vector2
  clientPosition: THREE.Vector2
  pressConfirmThreshold: number
  pressStartThreshold: number
  buttons: any
  holdTimeout: number
  startTime: number
  successTimeout: number
  constructor(e, t = 500) {
    ;(this.onEventCallback = e),
      (this.state = O.IDLE),
      (this.ndcStartPosition = new THREE.Vector2()),
      (this.pointerDelta = new THREE.Vector2()),
      (this.ndcPosition = new THREE.Vector2()),
      (this.clientPosition = new THREE.Vector2()),
      (this.pressConfirmThreshold = this.pressStartThreshold = Math.max(t, 1e-4))
  }
  start(e) {
    this.state !== O.IDLE && this.stop(),
      this.state === O.IDLE &&
        0 == (e.buttons & (e.buttons - 1)) &&
        (this.ndcStartPosition.copy(e.position),
        (this.state = O.WAITING),
        (this.buttons = e.buttons),
        this.pointerDelta.set(0, 0),
        this.ndcPosition.copy(e.position),
        this.clientPosition.copy(e.clientPosition),
        (this.holdTimeout = window.setTimeout(() => {
          ;(this.state = O.STARTED),
            A.debug("STARTED"),
            (this.startTime = Date.now()),
            this.progress(0),
            this.onEventCallback(new LongPressStartEvent(e.position, e.clientPosition, e.buttons)),
            (this.successTimeout = window.setTimeout(() => {
              A.debug("SUCCESSFUL"),
                (this.state = O.SUCCESSFUL),
                this.progress(1),
                this.onEventCallback(new LongPressSuccessEvent(this.ndcPosition, this.clientPosition))
            }, this.pressConfirmThreshold))
        }, this.pressStartThreshold)))
  }
  stop() {
    const e = this.state
    if (((this.state = O.IDLE), window.clearTimeout(this.holdTimeout), window.clearTimeout(this.successTimeout), e > O.WAITING)) {
      A.debug("DONE, cancelled:", e < O.SUCCESSFUL)
      const t = e < O.SUCCESSFUL
      this.onEventCallback(new LongPressEndEvent(this.ndcPosition, this.clientPosition, t))
    }
  }
  onMove(e) {
    const t = this.state === O.STARTED || this.state === O.WAITING,
      i = this.state === O.STARTED || this.state === O.SUCCESSFUL
    ;(t || i) &&
      (this.ndcPosition.copy(e.position), this.clientPosition.copy(e.clientPosition), this.pointerDelta.copy(this.ndcPosition).sub(this.ndcStartPosition)),
      t && this.pointerDelta.length() > 0.1
        ? this.stop()
        : i && this.onEventCallback(new LongPressMoveEvent(this.ndcPosition, this.clientPosition, this.pointerDelta, this.buttons))
  }
  tick() {
    if (this.state === O.STARTED) {
      const e = 1 - (this.pressStartThreshold - (Date.now() - this.startTime)) / this.pressStartThreshold
      this.progress(Math.min(1, e))
    }
  }
  progress(e) {
    this.onEventCallback(new LongPressProgressEvent(this.ndcPosition, this.clientPosition, this.pointerDelta, this.buttons, e))
  }
}
import RawPointersEvent from "../event/RawPointersEvent"
import SettingsModule from "./SettingsModule"

import SymbolList from "../SymbolList"
var P = {
  0: "NONE",
  1: "CLICK_DRAG_LONGPRESS",
  2: "PINCH_ROTATE",
  3: "MULTI_SWIPE_ONLY",
  CLICK_DRAG_LONGPRESS: 1,
  MULTI_SWIPE_ONLY: 3,
  NONE: 0,
  PINCH_ROTATE: 2
}

class InputGesture {
  activeGesture: any
  pointers: any[]
  couldBeClick: boolean
  onEventCallback: any
  clicker: ClickGesturer
  longPress: LongPressGesturer
  dragger: DragGesturer
  pincher: PinchGesturer
  rotater: RotateGesturer
  multiswiper: MultiSwipeGesturer
  constructor() {
    ;(this.activeGesture = P.NONE), (this.pointers = []), (this.couldBeClick = !1)
  }
  async init(e, t, i: EngineContext) {
    ;(this.onEventCallback = t),
      (this.clicker = new ClickGesturer(e.dragThreshold)),
      (this.longPress = new LongPressGesturer(t, e.holdThreshold)),
      (this.dragger = new DragGesturer(t, e.dragThreshold)),
      (this.pincher = new PinchGesturer(e.pinchThreshold)),
      (this.rotater = new RotateGesturer(e.rotateThreshold)),
      (this.multiswiper = new MultiSwipeGesturer(e.dragThreshold))
    const n = await i.getModuleBySymbol<CanvasModule>(SymbolList.CANVAS)
    e.disableWheel || this.bindWheelHandlers(n.element)
  }
  get activePointers() {
    return this.pointers.length
  }
  onPointerChange(e) {
    this.isMoveEvent(e) ? this.onPointerMove(e) : this.onPointerButton(e)
  }
  isMoveEvent(e) {
    return !e.hasOwnProperty("down")
  }
  onPointerMove(e) {
    this.movePointer(e.id, e.position, e.clientPosition, e.buttons)
  }
  onPointerButton(e) {
    e.down ? this.addPointer(e.id, e.position, e.clientPosition, e.button) : this.removePointer(e.id, e.button)
  }
  bindWheelHandlers(e) {
    e.addEventListener("wheel", e => {
      e.preventDefault(),
        this.onEventCallback(
          new ScrollEvent(
            { x: e.clientX, y: e.clientY },
            {
              x: this.normalizeWheelDelta(e.deltaMode, e.deltaX),
              y: this.normalizeWheelDelta(e.deltaMode, e.deltaY)
            }
          )
        )
    })
  }
  normalizeWheelDelta(e, t) {
    if (e === WheelEvent.DOM_DELTA_LINE) {
      return 0.7 * t * t * t + 13 * t
    }
    return t
  }
  addPointer(e, t, i, n) {
    const s = o.AF(n)
    if (!s) return
    const r = this.getPointer(e)
    r && 0 == (r.buttons & s)
      ? ((r.buttons |= s), r.activeButtons++)
      : this.pointers.push({
          id: e,
          position: new THREE.Vector2(t.x, t.y),
          clientPosition: new THREE.Vector2(i.x, i.y),
          buttons: s,
          activeButtons: 1
        }),
      this.toggleGestures()
  }
  removePointer(e, t) {
    const i = o.AF(t)
    if (!i) return
    const n = this.getPointerIndex(e)
    if (-1 !== n) {
      const e = this.pointers[n]
      0 != (e.buttons & i) && ((e.buttons &= ~i), e.activeButtons--), e.activeButtons || this.pointers.splice(n, 1), this.toggleGestures()
    }
  }
  movePointer(e, t, i, n) {
    const s = this.getPointer(e)
    if (s)
      switch (
        (s.position.copy(t),
        s.clientPosition.copy(i),
        s.buttons !== n ? this.updateOffscreenPointer(s, n) : this.onEventCallback(new RawPointersEvent(this.pointers)),
        this.activeGesture)
      ) {
        case P.CLICK_DRAG_LONGPRESS:
          const e = this.clicker.onMove(s)
          e && this.onEventCallback(e)
          const t = this.dragger.onMove(s)
          t && this.onEventCallback(t), this.longPress.onMove(s)
          break
        case P.PINCH_ROTATE:
          const i = this.pincher.onMove(this.pointers[0], this.pointers[1]),
            n = this.rotater.onMove(this.pointers[0], this.pointers[1])
          i && this.onEventCallback(i), n && this.onEventCallback(n)
          break
        case P.MULTI_SWIPE_ONLY:
          const r = this.multiswiper.onMove(this.pointers)
          r && this.onEventCallback(r)
      }
  }
  getPointer(e) {
    const t = this.getPointerIndex(e)
    if (-1 !== t) return this.pointers[t]
  }
  toggleGestures() {
    this.onEventCallback(new RawPointersEvent(this.pointers))
    const e = this.activeGesture
    if (((this.activeGesture = this.pointers.length), e === P.CLICK_DRAG_LONGPRESS && this.activeGesture === P.NONE && this.couldBeClick)) {
      const e = this.clicker.stop()
      e && this.onEventCallback(e)
    }
    if (((this.couldBeClick = e === P.NONE && this.activeGesture === P.CLICK_DRAG_LONGPRESS), this.activeGesture === P.CLICK_DRAG_LONGPRESS)) {
      const e = this.clicker.start(this.pointers[0])
      e && this.onEventCallback(e)
      const t = this.dragger.start(this.pointers[0])
      t && this.onEventCallback(t), this.longPress.start(this.pointers[0])
    } else if (e === P.CLICK_DRAG_LONGPRESS) {
      const e = this.dragger.stop()
      this.longPress.stop(), this.onEventCallback(e)
    }
    this.activeGesture === P.PINCH_ROTATE
      ? (this.pincher.start(this.pointers[0], this.pointers[1]), this.rotater.start(this.pointers[0], this.pointers[1]), this.multiswiper.start(this.pointers))
      : e === P.PINCH_ROTATE &&
        (this.onEventCallback(this.pincher.stop()), this.onEventCallback(this.rotater.stop()), this.onEventCallback(this.multiswiper.stop())),
      this.activeGesture === P.MULTI_SWIPE_ONLY
        ? this.multiswiper.start(this.pointers)
        : e === P.MULTI_SWIPE_ONLY && this.onEventCallback(this.multiswiper.stop())
  }
  getPointerIndex(e) {
    for (let t = 0; t < this.pointers.length; t++) {
      if (this.pointers[t].id === e) return t
    }
    return -1
  }
  updateOffscreenPointer(e, t) {
    if (((e.buttons = t), 0 === t)) {
      const t = this.getPointerIndex(e.id)
      this.pointers.splice(t, 1), this.toggleGestures()
    }
  }
  tick() {
    this.longPress.tick()
  }
}
import OrderedMap from "../utils/OrderedMap"
import CanvasData from "../data/CanvasData"
import RaycasterModule from "./RaycasterModule"
import { PointerButtonEvent, PointerMoveEvent } from "../event/PointerEvent"
import pointDeviceEnum from "../enum/pointDevice.enum"
import hotKeyEnum, { KeyState } from "../enum/hotKey.enum"
import EngineContext from "../EngineContext"
import CanvasModule from "./CanvasModule"
import PortalPuckMesh from "../mesh/PortalPuckMesh"
export class InputSubscription {
  _renew: any
  _cancel: any
  active: any
  constructor(e, t, i) {
    this._renew = e
    this._cancel = t
    this.active = i
  }
  renew() {
    this.active() || this._renew()
  }
  cancel() {
    this.active() && this._cancel()
  }
}
export default class InputIniModule extends Module {
  fallbackHandlerMap: Record<string, Function[]>
  meshHandlerMap: {}
  priorityHandlerMap: Record<string, any>
  unfilteredHandlerMap: Record<string, Function[]>
  captureHandlerMap: Record<string, Function[]>
  gesturing: boolean
  gestureCapture: OrderedMap
  activeIntersections: OrderedMap
  eventTypeLookup: TypeLookup
  meshTypeLookup: TypeLookup
  hoveredMesh: Partial<THREE.Intersection>
  registerUnfilteredHandler: (e: any, t: any) => InputSubscription
  registerMesh: (e: any, t: any, i?: any) => void
  raycaster: RaycasterModule
  unregisterMesh: (e: THREE.Mesh) => void
  onPointerEvent: (e: any) => void
  inputGesture: InputGesture
  constructor() {
    super(...arguments), (this.name = "input-ini")
    this.fallbackHandlerMap = {}
    this.meshHandlerMap = {}
    this.priorityHandlerMap = {}
    this.unfilteredHandlerMap = {}
    this.captureHandlerMap = {}
    this.gesturing = !1
    this.gestureCapture = new OrderedMap(e => e.object.id)
    this.activeIntersections = new OrderedMap(e => e.object.id)
    this.eventTypeLookup = new TypeLookup()
    this.meshTypeLookup = new TypeLookup()
    this.hoveredMesh = {
      object: null,
      instanceId: null,
      index: null
    }
    this.registerUnfilteredHandler = (e, t) => {
      this.insertHandler(e, this.unfilteredHandlerMap, t)
      const i = this.eventTypeLookup.getKeyByType(e)
      return new InputSubscription(
        () => this.registerUnfilteredHandler(e, t),
        () => this.unregisterUnfilteredHandler(e, t),
        () => -1 !== this.unfilteredHandlerMap[i].indexOf(t)
      )
    }
    this.registerMesh = <T extends THREE.Mesh>(e: T, t: boolean, i?) => {
      this.raycaster.targets.addTarget(e, t, i)
    }
    this.unregisterMesh = (e: THREE.Mesh) => {
      this.raycaster.targets.removeTarget(e)
    }
    this.onPointerEvent = e => {
      const t = !e.hasOwnProperty("down"),
        i = !t && e.down,
        n = !i && !t
      if (t || i) {
        this.raycaster.pointer.updatePointer(e.position), this.activeIntersections.clear()
        for (const e of this.raycaster.pointer.cast()) this.activeIntersections.add(e)
        if (!this.gesturing) {
          this.gestureCapture.clear()
          for (const e of this.activeIntersections) this.gestureCapture.add(e)
          this.updateHoveredMesh()
        }
        i && (this.gesturing = !0), this.onEvent(e)
      }
      this.inputGesture.onPointerChange(e),
        n && this.onEvent(e),
        0 === this.inputGesture.activePointers &&
          (this.activeIntersections.clear(), this.gestureCapture.clear(), this.gesturing && this.updateHoveredMesh(), (this.gesturing = !1))
    }
    this.onEvent = e => {
      const t = this.eventTypeLookup.getKeyByInstance(e),
        i = this.captureHandlerMap[t]
      if (i && i.length > 0) {
        for (const t of i) t(e)
        return void (i.length = 0)
      }
      const n = this.unfilteredHandlerMap[t]
      if (n) for (const t of n) t(e)
      const s = this.iterateMeshCallbacks(e, this.gesturing ? this.gestureCapture : this.activeIntersections),
        r = this.fallbackHandlerMap[t]
      if (!s && r) for (const t of r) t(e)
    }
  }
  onEvent: any
  async init(e, t: EngineContext) {
    const i = { disableWheel: !!e.disableWheel }
    const n = await t.getModuleBySymbol<CanvasModule>(SymbolList.CANVAS)
    const s = await t.market.waitForData(CanvasData)
    this.raycaster = await t.getModule(RaycasterModule)
    new InputPointer({ pointerPreventDefault: e.pointerPreventDefault }, n.element, s, this.onPointerEvent)
    new InputKey(this.onEvent)
    this.inputGesture = new InputGesture()
    this.inputGesture.init(i, this.onEvent, t)
  }
  registerHandler(e, t) {
    this.insertHandler(e, this.fallbackHandlerMap, t)
    const i = this.eventTypeLookup.getKeyByType(e, !0)
    return new InputSubscription(
      () => this.registerHandler(e, t),
      () => this.unregisterHandler(e, t),
      () => -1 !== this.fallbackHandlerMap[i].indexOf(t)
    )
  }
  unregisterHandler(e, t) {
    this.removeHandler(e, this.fallbackHandlerMap, t)
  }
  registerMeshHandler(e, t, i) {
    return this._registerMeshHandler(e, { comparator: t, callback: i })
  }
  _registerMeshHandler(e, t) {
    const i = this.eventTypeLookup.getKeyByType(e, !0)
    this.meshHandlerMap[i] || (this.meshHandlerMap[i] = [])
    const n = this.meshHandlerMap[i]
    n.push(t)
    return new InputSubscription(
      () => this._registerMeshHandler(e, t),
      () => this.unregisterMeshHandler(e, t),
      () => -1 !== n.indexOf(t)
    )
  }
  unregisterMeshHandler(e, t) {
    const i = this.eventTypeLookup.getKeyByType(e, !0)
    if (this.meshHandlerMap[i]) {
      const e = this.meshHandlerMap[i],
        n = e.indexOf(t)
      n > -1 && e.splice(n, 1)
    }
  }
  registerPriorityHandler(e, t, i) {
    const n = this.eventTypeLookup.getKeyByType(e, !0),
      r = this.meshTypeLookup.getKeyByType(t, !0)
    this.priorityHandlerMap[n] || (this.priorityHandlerMap[n] = {})
    const o = this.priorityHandlerMap[n]
    if (o[r]) {
      const i = funcUtil.getProtoName(e),
        n = funcUtil.getProtoName(t)
      throw Error(`${i} already has a priority handler registered for mesh type: ${n}`)
    }
    return (
      (o[r] = i),
      new InputSubscription(
        () => this.registerPriorityHandler(e, t, i),
        () => this.unregisterPriorityHandler(e, t, i),
        () => void 0 !== o[r]
      )
    )
  }
  unregisterPriorityHandler(e, t, i) {
    const n = this.eventTypeLookup.getKeyByType(e),
      s = this.priorityHandlerMap[n]
    if (s) {
      const e = this.meshTypeLookup.getKeyByType(t),
        n = s[e]
      n && i === n && delete s[e]
    }
  }
  unregisterUnfilteredHandler(e, t) {
    this.removeHandler(e, this.unfilteredHandlerMap, t)
  }
  captureNext(e, t) {
    this.insertHandler(e, this.captureHandlerMap, t)
    return t
  }
  removeCaptureHandler(e, t) {
    this.removeHandler(e, this.captureHandlerMap, t)
  }
  registerSnappingMesh(e) {
    this.raycaster.snapping.addMesh(e)
  }
  updateHoveredMesh() {
    const e: THREE.Intersection = this.activeIntersections.getByIndex(0),
      t = e && e.object === this.hoveredMesh.object && e.instanceId === this.hoveredMesh.instanceId && e.index === this.hoveredMesh.index
    let i = !1
    if (this.hoveredMesh.object && (void 0 === e || !t)) {
      const t = this.getMeshHandler(UnhoverEvent, funcUtil.getConstructor(this.hoveredMesh.object), this.priorityHandlerMap)
      if ((t && (i = t(new UnhoverEvent(), this.hoveredMesh.object, e) || !1), !i)) {
        const t = this.meshHandlerMap[this.eventTypeLookup.getKeyByType(UnhoverEvent)]
        if (t) for (const i of t) i.comparator.compare(this.hoveredMesh.object) && i.callback(new UnhoverEvent(), this.hoveredMesh.object, e)
      }
    }
    let n = !1
    if (e && !t) {
      const t = this.getMeshHandler(HoverEvent, funcUtil.getConstructor(e.object), this.priorityHandlerMap)
      if ((t && (n = t(new HoverEvent(), e.object, e) || !1), !n)) {
        const t = this.meshHandlerMap[this.eventTypeLookup.getKeyByType(HoverEvent)]
        if (t) for (const i of t) i.comparator.compare(e.object) && i.callback(new HoverEvent(), e.object, e)
      }
    }
    this.hoveredMesh.object = (e && e.object) || null
    this.hoveredMesh.instanceId = null == e ? void 0 : e.instanceId
    this.hoveredMesh.index = null == e ? void 0 : e.index
  }
  iterateMeshCallbacks(e, t) {
    let i = !1
    const n = this.eventTypeLookup.getKeyByInstance(e)
    for (let s = 0; s < t.count(); s++) {
      const r = t.getByIndex(s)
      if (!r) continue
      if (i) break
      const o = r.object
      const a = this.activeIntersections.get(o.id) || r
      for (const t in this.priorityHandlerMap[n])
        if (r.object instanceof this.meshTypeLookup.getTypeByKey(t)) {
          const s = this.priorityHandlerMap[n] && this.priorityHandlerMap[n][t]
          if (s && ((i = !0), s(e, o, a))) return !0
        }
      const l = this.meshHandlerMap[n]
      if (l)
        for (const t of l) {
          if (t.comparator.compare(o)) {
            const n = t.callback(e, o, a)
            ;(n || void 0 === n) && (i = !0)
          }
        }
    }
    return i
  }
  insertHandler(e, t, i) {
    const n = this.eventTypeLookup.getKeyByType(e, !0)
    t[n] || (t[n] = []), t[n].push(i)
  }
  removeHandler(e, t, i) {
    const n = t[this.eventTypeLookup.getKeyByType(e)]
    if (n)
      for (let e = 0; e < n.length; e++)
        if (n[e] === i) {
          n.splice(e, 1)
          break
        }
  }
  getMeshHandler(e, t, i) {
    const n = i[this.eventTypeLookup.getKeyByType(e)]
    if (n) {
      return n[this.meshTypeLookup.getKeyByType(t)]
    }
    return null
  }
  onUpdate() {
    this.inputGesture.tick()
  }
}
